//
//  ViewController.m
//  block的使用总结
//
//  Created by 唐斌 on 2018/2/2.
//  Copyright © 2018年 唐斌科技有限公司. All rights reserved.
//

#import "ViewController.h"
#import "SecondViewController.h"
#import "NavigationViewController.h"
#import "BlockTool.h"

typedef int aint;
////1.定义无返回值,有一个字符串参数的名为Myblock的block类型
//typedef void(^Myblock)(NSString* blockStr);

//定义有返回值,有一个字符串参数blockStr的名为blockWithStringReturn的block类型
typedef NSString* (^blockWithStringReturn)(NSString* blockStr);


@interface ViewController ()

//用Myblock类型声明一个名为myblock的block变量.
@property(nonatomic,copy)Myblock  myblock;

@property(nonatomic,copy)blockWithStringReturn  myBlockWithReturn;
//@property(nonatomic,assign)aint  aintNumber;
@property(nonatomic,copy)NSString*  namestring;

//控制器属性,保存后调用该控制器的block属性
@property(nonatomic,strong)SecondViewController *viewC2;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self useBlock1];
//    [self usingBlock];
//    [self useBlock2];
//    [self usingBlockWithAviodingRetainCycle];
    [self changeOutsideBlockPropertyValue];
//    ViewController *vc = [[ViewController alloc]init];
//    [vc eat:^(NSString *blockStr) {
//        NSLog(@"内容是%@",blockStr);
//    }];
//    [self setMyblock:^(NSString *blockStr) {
//        NSLog(@"2内容是%@",blockStr);
//    }];
    
}

//对toolblock类的ablock属性进行赋值并调用
-(void)useBlock1{
    BlockTool* blockTool = [[BlockTool alloc]init];
    //对ablock属性进行赋值
//    [blockTool setABlock:^(NSString *food) {
//        NSLog(@"内容是%@",food);
//    }];
//
//    //调用
//    blockTool.aBlock(@"水果");
    
//    [blockTool eat:^(NSString *food) {
//        NSLog(@"内容是%@",food);
//    }];
    
    [blockTool eat:^(NSString *food) {
        
        
        NSLog(@"吃的内容是%@",food);
    }];
    
}

#pragma mark 1.给block变量属性赋值一个block代码块,并住其他地方调用
-(void)usingBlock{
/*
    什么是block?
    闭包(block):闭包就是获取其他函数局部变量的匿名函数.
    block格式:
 返回值类型(^block变量名)(形参列表) = ^(形参列表){
 
 }
    */
    
//  定义一个block变量,并且给block变量赋值一个代码块
//    有参数无返回值
//    void (^myBlock2)(NSString* )
  _myblock = ^(NSString *str){

NSLog(@"内容是%@",str);
        
    };
   
    
}

#pragma mark 2.给block变量属性赋值一个block代码块,并住其他地方调用
-(void)useBlock2{
    
    _myBlockWithReturn = ^(NSString *username){
     NSString *aName = [NSString stringWithFormat:@"他的名字是%@",username];
        NSLog(@"内容是%@",aName);
        
        return aName;
        
    };
    
}

#pragma mark - 2. 避免循环引用详解
-(void)usingBlockWithAviodingRetainCycle{
    //block内给当前控制器的属性赋值时避免循环引用.
    
//方法:myBlock内部引用了当前控制器的属性，想要解除循环引用，需要在block外部弱引用一下self
    __weak typeof(self) WeakSelf = self;
    
    _myBlockWithReturn = ^(NSString *namestr){
        //用weakself引用属性
        WeakSelf.namestring = namestr;
        NSLog(@"namestr内容是%@",namestr);
        return namestr;
        
    };
    
}

#pragma mark 4.block内修改外部变量
-(void)changeOutsideBlockPropertyValue{
     //Block不允许修改外部变量的值，这里所说的外部变量的值，指的是栈中指针的内存地址。__block 所起到的作用就是只要观察到该变量被 block 所持有，就将“外部变量”在栈中的内存地址放到了堆中。进而在block内部也可以修改外部变量的值
    
    //block内修改block外部的局部变量的值时避免循环引用,用__block修饰要改的局部变量就行.
   __block NSString *namestringOut = @"中国";
    _myBlockWithReturn = ^(NSString *namestr){
    
        namestringOut = @"美国";
        NSLog(@"namestr内容是%@",namestringOut);
        return namestringOut;
    };
}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    _myBlockWithReturn(@"sds");
    //调用block代码块,并传入一个字符串作为参数.
//     _myblock(@"一个block打印的字符串");
//    _myBlockWithReturn(@"王者刘德华");
//    _myBlockWithReturn(@"");
    
}

- (IBAction)jumpToVC2BtnClicked:(id)sender {
    
    SecondViewController *vc2 = [[SecondViewController alloc]init];
//    vc2.passValueBlock1(@"");
    __weak typeof(self) weakSelf = self;
    //给vc2的block属性赋值
    vc2.passValueBlock1 = ^NSString *(NSString *nameString) {
     
        weakSelf.nameStringLabel.text = nameString;
        
        return nameString;
    };

    [self presentViewController:vc2 animated:YES completion:nil];
    
}


- (void)eat:(Myblock)block{
    block(@"zansan");
//    NSLog(@"内容是%@",<#para#>);
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end
